import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;
import java.util.Vector;

// Tower main class & projectile class
/********************
 *   Tower class	*
 ********************/
public abstract class Tower extends Entity 
{
	// Range of the tower
	protected int range;
	// Displays/hide the range of the tower
	protected Boolean showRange = false;
	// Color of the range circle
	protected Color rangeColor;
	// Opacity of the rangeColor
	private int opacity = 10;
	
	// Position & center of the circle of range
	protected Vector2 circlePos;
	protected Vector2 circleCenter;
	
	// Rate of attack
	protected int attackRate;
	// Speed of the projectile
	protected int projSpeed;
	// Target of the tower
	Creature currentTarget, prevTarget;
	// Random
	Random rand = new Random();
	// Projectiles of the tower
	Vector<Projectile> projectiles = new Vector<Projectile>();
	// Attack timer
	int timer = 0;
	// Kill number
	int kills = 0;
	
	// Constructor with 2 floats
	public Tower(Vector2 position)
	{
		this.position = position;
		life = 1;
		maxLife = 1;
	}
	
	// Constructor with 2 integers
	public Tower(Point position)
	{
		this.position = new Vector2(position.x, position.y);
		life = 1;
		maxLife = 1;
	}
	
	// Clear all projectiles all the tower
	public void ClearProjectiles()
	{
		projectiles.clear();
	}
	
	// Update method
	public void Update()
	{
		AttackHandler();
		UpdateProj();
	}
	
	// Shoot one projectile
	public void Attack()
	{
		projectiles.add(new Projectile(rand.nextInt(10)+4, damage, Color.black, projSpeed, new Vector2(position.x + size/2, position.y + size/2), currentTarget, this));
	}

	// Draw method
	public void Draw(Graphics g)
	{
		// Draws the tower
		g.setColor(color);
		g.fillRect((int)position.x, (int)position.y, size, size);
		
		// Draws the range of the tower
		if(showRange)
		{
			Color oldColor = g.getColor();
			g.setColor(new Color(0, 0, 0, opacity));
			g.fillOval((int)circlePos.x, (int)circlePos.y, range, range);
			g.setColor(oldColor);
		}
		
		// Draws its projectiles
		for(int i = 0; i < projectiles.size(); i++)
			projectiles.elementAt(i).Draw(g);
	}
	
	// Handles the attack timer & targeting system
	void AttackHandler()
	{
		// Increments timer
		timer++;
		
		prevTarget = currentTarget;
		currentTarget = Game.GetNearestCreature(this);
		
		if(currentTarget == null && currentTarget != prevTarget)
			prevTarget.setColor(Color.black);
		
		if(currentTarget != null)
			currentTarget.setColor(Color.red);
		
		// Tower is ready to shoot and has a target
		if(timer > attackRate && currentTarget != null)
		{
			timer = 0;
			Attack();
		}
	}
	
	// Updates all the projectiles of the tower
	void UpdateProj()
	{
		// If there is no more target, remove projectiles
		if(currentTarget == null)
			ClearProjectiles();
		
		// Update each projectile
		for(int i = 0; i < projectiles.size(); i++)
			projectiles.elementAt(i).Update();
		
		
		// Removes wasted projectiles
		for(int i = 0; i < projectiles.size(); i++)
			if (projectiles.elementAt(i).Wasted())
				projectiles.remove(i);
	}
	
	public String GetType()
	{
		return "tower";
	}
	
	// Getter & Setter
	public int getRange() {return range;}
	public Vector2 getCirclePos() {return circlePos;}
	public Boolean getShowRange() {return showRange;}
	
	public void setRange(int range) {this.range = range;}
	public void setCirclePos(Vector2 circlePos) {this.circlePos = circlePos;}
	public void setShowRange(Boolean showRange) {this.showRange = showRange;}

	/********************
	 * Projectile class *
	 ********************/
	public class Projectile
	{
		private int size;
		private int damage;
		private Color color;
		private float speed;
		private Vector2 position;
		Creature target;
		Tower source;
		
/*		// Delay in ms (delay * 16 ms) before the projectile is deleted
		int delay = 1;
		int delayTimer = -1; */
		
		public Projectile(int size, int damage, Color color, float speed, Vector2 position, Creature target, Tower source)
		{
			this.size = size;
			this.damage = damage;
			this.color = color;
			this.speed = speed;
			this.position = position;
			this.target = target;
			this.source = source;
		}
		
		// Should the projectile be removed ?
		// (Out of screen, collided or no more target)
		public Boolean Wasted()
		{
			// If the projectile did collide, deal the damage to the target and delete projectile
			if(Collide())
			{
				target.DealDamage(damage, source);
				return true;
			}
			// If the projectile is out of the screen, delete projectile
			else if(OutOfScreen())
				return true;
			
			return false;
		}
		
		// Is the projectile out of the screen bounds ?
		Boolean OutOfScreen()
		{
			return position.x < 0 || position.x + size > Game.WIDTH || position.y < 0 || position.y + size > Game.HEIGHT;
		}
		
		// Has the projectile collided with its target ?
		public Boolean Collide()
		{
			// No target found, quit
			if(target == null)
				return false;

			// Collide when the hitbox of the projectile meets the center of the target
			return (Math.sqrt(Math.pow(Math.abs(position.x - target.getPosition().x), 2) + Math.pow(Math.abs(position.y - target.getPosition().y), 2) ) <= size ); 
		}
		
		// Update method
		public void Update()
		{

			// Projectile aims the center of the target, not its hitbox 
			Vector2 dir = new Vector2(target.getPosition().x - position.x, target.getPosition().y - position.y);
			// Getting the unit vector
			dir.Normalize();
			// Multiplying it by the speed
			dir.Multiply(speed);
			// Updating position
			position.Add(dir);
		}
		
		// Draw method
		public void Draw(Graphics g)
		{
			g.setColor(color);
			g.fillOval((int)(position.x), (int)(position.y), size, size);
		}
	}
}